package MyHttp;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.HashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class HttpServer {
    //对应的Servlet的容器
    private HashMap<String, Servlet> servletPool = new HashMap<>();
    //声明了一个私有实例变量 servletPool，它是一个 HashMap，用于将 String 键映射到 Servlet 值。
    private static class runtimeException extends RuntimeException{ //自定义异常
        public runtimeException() {
        }

        public runtimeException(String message) {
            super(message);
        }

        public runtimeException(String message, Throwable cause) {
            super(message, cause);
        }

        public runtimeException(Throwable cause) {
            super(cause);
        }

        public runtimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
            super(message, cause, enableSuppression, writableStackTrace);
        }
    }
    //构造方法 port监听的接口
    public HttpServer(int port) throws IOException {
        //捕获 IOException，因为创建服务器套接字或接受连接时可能会发生各种问题（例如，端口被占用、权限不足）。
        if (port < 1 || port > 65535) {
            throw new RuntimeException("端口错误，端口必须在1到65535之间");
        }
        ServerSocket serverSocket = new ServerSocket(port);
        //这是 Java 中用于创建服务器端套接字的类。服务器套接字用于监听传入的客户端连接请求。
        //构造具有50个线程的线程池
        ExecutorService pool = Executors.newFixedThreadPool(50);
        System.out.println("HTTP服务器启动，监听端口：" + port);
        while (true) {
            Socket clientSocket = serverSocket.accept();
            //阻塞方法，等待客户端连接。返回一个 Socket 对象，表示与客户端的连接。
            //System.out.println("接收到来自客户端的请求");
            //因为存在浏览器多次请求的问题,我们先判断一下接受到的客户端socket是否可用
            if (clientSocket != null && !clientSocket.isClosed()) {
                Runnable r = () -> {//lambda表达式 创建了一个Runnabl任务来处理客户端请求
                    try {
                        handleClient(clientSocket);
                    } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                };
                pool.submit(r);
            }
        }
    }
    //获取对应的servlet
    private synchronized Servlet getServlet(String servletName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        // 构造完整的类名
        String className = "MyHttp." + servletName.substring(0, 1).toUpperCase() + servletName.substring(1) + "Servlet";
        //检查是否已缓存该Servlet
        if (servletPool.containsKey(className)) {
            return servletPool.get(className);
        }
        //如果未缓存，则通过反射创建新实例
        Class servletClass = Class.forName(className);
        //根据字符串servletName指定的类名，从类路径（classpath）中加载对应的类。
        Servlet servlet = (Servlet) servletClass.newInstance();
        //通过反射创建该类的一个新实例。返回的是Object类型，需要强制转换为Servlet类型（因为Servlet类通常实现了javax.servlet.Servlet接口
        // 将新实例存入缓存
        servletPool.put(className, servlet);
        return servlet;
    }

    private void handleClient(Socket clientSocket) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        InputStream in = clientSocket.getInputStream();  //返回套接字的输入流，用于读取数据
        OutputStream out = clientSocket.getOutputStream();  //返回套接字的输出流，用于写入数据。

        // 解析请求行
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        //字节流（InputStream） → 字符流（InputStreamReader） → 带缓冲的字符流（BufferedReader）
        //带缓冲的字符输入流，通过缓冲区减少 IO 次数，提高读取效率。
        String firstLine = reader.readLine();
        if (firstLine == null) {
            writeResponse(out, 400, "Bad Request", "text/html", "<h1>Bad Request</h1>".getBytes());
            return;
        }
        String[] parts = firstLine.split(" "); //GET /test1.html HTTP/1.1
        String method = parts[0];
        String requestUrl = parts[1];// /test1.html

        // 解析请求头和请求体（POST）
        String requestBody = "";
        if ("POST".equals(method)) {
            // 读取Content-Length
            int contentLength = 0;
            String line;
            while ((line = reader.readLine()) != null && !line.isEmpty()) {
                if (line.startsWith("Content-Length:")) {
                    contentLength = Integer.parseInt(line.split(": ")[1]);
                }
            }
            // 读取请求体
            if (contentLength > 0) {
                char[] bodyBuffer = new char[contentLength];
                reader.read(bodyBuffer);
                requestBody = new String(bodyBuffer);
            }
        }

        // 动态资源处理（Servlet）
        if (requestUrl.startsWith("/servlet/")) {
            //System.out.println(requestUrl);
            String servletName = requestUrl.substring("/servlet/".length());//   /servlet/login得到名字为login
            if (servletName.contains("?")) {
                servletName = servletName.substring(0, servletName.indexOf("?"));
            }
            Servlet servlet = getServlet(servletName);  //通过 getServlet 方法利用反射创建 Servlet 实例（如 LoginServlet）。
            String response = servlet.doRequest(method, requestUrl, requestBody);
            writeResponse(out, 200, "OK", "text/html", response.getBytes());
            return;
        }

        // 静态资源处理
        String contentType = "text/html";
        if (requestUrl.endsWith(".jpg") || requestUrl.endsWith(".jpeg")) {
            contentType = "image/jpeg";
        } else if (requestUrl.endsWith(".gif")) {
            contentType = "image/gif";
        } else if (requestUrl.endsWith(".css")) {
            contentType = "text/css";
        } else if (requestUrl.endsWith(".js")) {
            contentType = "application/javascript";//字节流类型
        }

        String resourcePath = requestUrl.equals("/") ? "index.html" : requestUrl.substring(1);
        //读取资源的内容
        URL resourceUrl = getClass().getClassLoader().getResource(resourcePath);//找到本地文件夹路径
        if (resourceUrl == null) {
            writeResponse(out, 404, "Not Found", "text/html", "<h1>File Not Found</h1>".getBytes());
            return;
        }

        try (InputStream resourceIn = resourceUrl.openStream()) {
            byte[] content = resourceIn.readAllBytes();  //将输入流中的所有字节读取到一个字节数组中
            writeResponse(out, 200, "OK", contentType, content); //封装 HTTP 响应并发送给客户端
        } catch (IOException e) {
            writeResponse(out, 500, "Internal Server Error", "text/html", "<h1>Server Error</h1>".getBytes());
        }
    }

    private void writeResponse(OutputStream out, int status, String desc, String contentType, byte[] content) throws IOException {
        out.write(("HTTP/1.1 " + status + " " + desc + "\r\n").getBytes());  //\r\n效果是：先回到行首（\r），然后换到下一行（\n）
        out.write(("Content-Type: " + contentType + "; charset=UTF-8\r\n").getBytes());
        out.write(("Content-Length: " + content.length + "\r\n").getBytes());
        out.write("\r\n".getBytes());  //用空行分割内容
        out.write(content);
        out.flush(); //强制刷新
        out.close();
    }

    public static void main(String[] args) throws IOException {
        new HttpServer(8080); // 示例端口
    }
}